﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CPPEI.ETL.TaskAgent.Threads
{
    /// <summary>
    /// 运行任务的线程
    /// </summary>
    static class RunThread
    {
        private static bool s_isStarted = false;
        private static bool s_isRunning = false;

        private static Thread s_thread;
        private static long s_lastTicks = 0;
        private static long s_interval = TimeSpan.FromSeconds(15).Ticks;
        private static long s_secondTicks = TimeSpan.FromSeconds(1).Ticks;
        private static long s_muniteTicks = TimeSpan.FromSeconds(60).Ticks;
        private static int s_runCounter = 0;

        private static EventWaitHandle s_waitHandle;

        public static void Start()
        {
            if (s_isStarted)
            {
                return;
            }

            Logger.DebugToTag(Library.LogTAG, "执行任务的线程启动");
            s_waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
            s_isRunning = true;
            s_isStarted = true;
            s_thread = new Thread(Running);
            s_thread.Start();

        }

        public static void Stop()
        {
            if (s_isRunning)
            {
                s_isRunning = false;
                s_waitHandle.WaitOne();
                s_waitHandle = null;
                s_isStarted = false;
            }
            Logger.DebugToTag(Library.LogTAG, "执行任务的线程结束");
        }

        private static void Running()
        {
            Logger.DebugToTag(Library.LogTAG, "执行任务的线程开始运行...");
            while (s_isRunning)
            {
                long nowTicks = DateTime.Now.Ticks;
                if(nowTicks - s_lastTicks > s_interval)
                {
                    // execute
                    RunTask();
                    s_lastTicks = DateTime.Now.Ticks;

                    s_runCounter++;
                    if(s_runCounter > 2)
                    {
                        // send request to server
                        HttpClient.Http.TestPostToServer();
                        s_runCounter = 0;
                    }
                }
                else
                {
                    Thread.Sleep(2000);
                }
            }

            s_waitHandle.Set();
            Logger.DebugToTag(Library.LogTAG, "执行任务的线程结束运行...");
        }

        private static void RunTask()
        {
            for (int taskIndex = 0; taskIndex < Cache.TaskList.Count; taskIndex++)
            {
                CPPEI.ETL.Domain.TaskProxy.Task task = Cache.TaskList[taskIndex];

                if (task.RunMode == CPPEI.ETL.Domain.DEF.TaskRunMode.Timer)
                {
                    // timer task run mode
                    RunTimerTask(task);
                }
                else if (task.RunMode == CPPEI.ETL.Domain.DEF.TaskRunMode.Alarm)
                {
                    // alarm task run mode
                    RunAlarmTask(task);
                }
            }
        }

        /// <summary>
        /// 运行定时器任务
        /// </summary>
        /// <param name="timerTask"></param>
        private static void RunTimerTask(CPPEI.ETL.Domain.TaskProxy.Task timerTask)
        {
            if(timerTask.RunModes == null || timerTask.RunModes.Count == 0)
            {
                return;
            }

            DateTime now = DateTime.Now;


            Domain.TaskProxy.TaskRunMode taskRunMode = timerTask.RunModes[0];
            DateTime executeTime = taskRunMode.TimerBeginTime.Value;

            #region 计算任务下一步执行时间
            if (taskRunMode.NextExecuteTime == null)
            {
                if (taskRunMode.TimerIntervalMode.Value == CPPEI.ETL.Domain.DEF.TaskTimerMode.Day)
                {
                    // 计算任务应该执行的时间
                    double days = (now - taskRunMode.TimerBeginTime.Value).TotalDays;
                    if (days > 0)
                    {
                        double divisor = (double)(days / taskRunMode.TimerInterval.Value);
                        double remainder = (double)(days % taskRunMode.TimerInterval.Value);

                        taskRunMode.NextExecuteTime = taskRunMode.TimerBeginTime.Value.AddDays(taskRunMode.TimerInterval.Value * (divisor + 1));
                    }
                    else
                    {
                        int divisor = 1;

                        taskRunMode.NextExecuteTime = taskRunMode.TimerBeginTime.Value.AddDays(taskRunMode.TimerInterval.Value * (divisor + 1));
                    }
                }
                else if (taskRunMode.TimerIntervalMode.Value == CPPEI.ETL.Domain.DEF.TaskTimerMode.Hour)
                {
                    // 小时的间隔模式
                    // 计算任务应该执行的时间
                    double hours = (now - taskRunMode.TimerBeginTime.Value).TotalHours;
                    if (hours > 0)
                    {
                        double divisor = (double)(hours / taskRunMode.TimerInterval.Value);
                        double remainder = (double)(hours % taskRunMode.TimerInterval.Value);

                        taskRunMode.NextExecuteTime = taskRunMode.TimerBeginTime.Value.AddHours(taskRunMode.TimerInterval.Value * (divisor + 1));
                    }
                    else
                    {
                        int divisor = 1;

                        taskRunMode.NextExecuteTime = taskRunMode.TimerBeginTime.Value.AddHours(taskRunMode.TimerInterval.Value * (divisor + 1));
                    }
                }
                else if (taskRunMode.TimerIntervalMode.Value == CPPEI.ETL.Domain.DEF.TaskTimerMode.Minute)
                {
                    // 分钟的间隔模式
                    // 计算任务应该执行的时间
                    if(taskRunMode.TimerBeginTime.Value.Second != 0)
                    {
                        taskRunMode.TimerBeginTime = new DateTime(taskRunMode.TimerBeginTime.Value.Year, 
                            taskRunMode.TimerBeginTime.Value.Month,
                            taskRunMode.TimerBeginTime.Value.Day,
                            taskRunMode.TimerBeginTime.Value.Hour,
                            taskRunMode.TimerBeginTime.Value.Minute, 0);
                    }
                    double minutes = (new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0) - taskRunMode.TimerBeginTime.Value).TotalMinutes;

                    if (minutes > 0)
                    {
                        double divisor = (double)(minutes / taskRunMode.TimerInterval.Value);
                        double remainder = (double)(minutes % taskRunMode.TimerInterval.Value);

                        Logger.InfoToTag(Library.LogTAG, string.Format("任务:{0},{1}的启动时间为:{2},距离当前时间:{3}的差值为:{4},增加倍数:{5}", timerTask.Id, timerTask.Name, taskRunMode.TimerBeginTime.Value, now, minutes, divisor + 1));

                        taskRunMode.NextExecuteTime = taskRunMode.TimerBeginTime.Value.AddMinutes(taskRunMode.TimerInterval.Value * (divisor + 1));
                    }
                    else
                    {
                        int divisor = 1;

                        Logger.InfoToTag(Library.LogTAG, string.Format("任务:{0},{1}的启动时间为:{2},距离当前时间:{3}的差值为:{4},增加倍数:{5}", timerTask.Id, timerTask.Name, taskRunMode.TimerBeginTime.Value, now, minutes, divisor + 1));

                        taskRunMode.NextExecuteTime = taskRunMode.TimerBeginTime.Value.AddMinutes(taskRunMode.TimerInterval.Value * (divisor + 1));
                    }
                }

                Logger.InfoToTag(Library.LogTAG, string.Format("设置任务:{0},{1}的下次执行时间为:{2}", timerTask.Id, timerTask.Name, taskRunMode.NextExecuteTime.Value));
            }
            #endregion

            #region 监测运行时间
            if (taskRunMode.NextExecuteTime != null)
            {
                // 任务还没有执行
                if (now.Year == taskRunMode.NextExecuteTime.Value.Year
                    && now.Month == taskRunMode.NextExecuteTime.Value.Month
                    && now.Day == taskRunMode.NextExecuteTime.Value.Day
                    && now.Hour == taskRunMode.NextExecuteTime.Value.Hour
                    && now.Minute == taskRunMode.NextExecuteTime.Value.Minute)
                {
                    // 执行任务

                    taskRunMode.LastExecutedTime = taskRunMode.NextExecuteTime;
                    taskRunMode.NextExecuteTime = null;
                    Logger.DebugToTag(Library.LogTAG, string.Format("执行任务:{0},{1}", timerTask.Id, timerTask.Name));
                    HttpClient.Http.PostToServer(timerTask);
                }
            }
            #endregion
        }

        /// <summary>
        /// 运行闹表任务
        /// </summary>
        /// <param name="alarmTask"></param>
        private static void RunAlarmTask(CPPEI.ETL.Domain.TaskProxy.Task alarmTask)
        {
            if (alarmTask.RunModes == null || alarmTask.RunModes.Count == 0)
            {
                return;
            }

            DateTime now = DateTime.Now;


            for (int index = 0; index < alarmTask.RunModes.Count; index++)
            {
                Domain.TaskProxy.TaskRunMode taskRunMode = alarmTask.RunModes[index];
                DateTime executeTime = taskRunMode.AlarmClock.Value;

                #region 计算任务下一步执行时间
                if (taskRunMode.NextExecuteTime == null)
                {
                    if (taskRunMode.AlarmMode.Value == CPPEI.ETL.Domain.DEF.TaskAlarmMode.PreYear)
                    {
                        #region year
                        if (taskRunMode.LastExecutedTime == null)
                        {
                            int days = DateTime.DaysInMonth(now.Year, taskRunMode.AlarmClock.Value.Month);

                            if (days > taskRunMode.AlarmClock.Value.Day)
                            {
                                // 当月天数超过预设的天
                                days = taskRunMode.AlarmClock.Value.Day;
                            }
                            // 每年
                            taskRunMode.NextExecuteTime = new DateTime(now.Year,
                                taskRunMode.AlarmClock.Value.Month,
                                days,
                                taskRunMode.AlarmClock.Value.Hour,
                                taskRunMode.AlarmClock.Value.Minute,
                                0);
                        }
                        else
                        {
                            int nextYear = now.Year + 1;
                            // 添加1年
                            int days = DateTime.DaysInMonth(nextYear, taskRunMode.AlarmClock.Value.Month);

                            if (days > taskRunMode.AlarmClock.Value.Day)
                            {
                                // 当月天数超过预设的天
                                days = taskRunMode.AlarmClock.Value.Day;
                            }
                            taskRunMode.NextExecuteTime = new DateTime(nextYear,
                                taskRunMode.AlarmClock.Value.Month,
                                days,
                                taskRunMode.AlarmClock.Value.Hour,
                                taskRunMode.AlarmClock.Value.Minute,
                                0);
                        }
                        #endregion
                    }
                    else if (taskRunMode.AlarmMode.Value == CPPEI.ETL.Domain.DEF.TaskAlarmMode.PreMonth)
                    {
                        #region month
                        if (taskRunMode.LastExecutedTime == null)
                        {
                            // 每月
                            int days = DateTime.DaysInMonth(now.Year, taskRunMode.AlarmClock.Value.Month);

                            if (days > taskRunMode.AlarmClock.Value.Day)
                            {
                                // 当月天数超过预设的天
                                days = taskRunMode.AlarmClock.Value.Day;
                            }
                            taskRunMode.NextExecuteTime = new DateTime(now.Year,
                                now.Month,
                                days,
                                taskRunMode.AlarmClock.Value.Hour,
                                taskRunMode.AlarmClock.Value.Minute,
                                0);
                        }
                        else
                        {
                            // 添加1月
                            int nextYear = now.Year;
                            int nextMonth = taskRunMode.AlarmClock.Value.Month + 1;
                            if(nextMonth > 12)
                            {
                                nextMonth = 1;
                                nextYear++;
                            }
                            int days = DateTime.DaysInMonth(nextYear, nextMonth);

                            if (days > taskRunMode.AlarmClock.Value.Day)
                            {
                                // 当月天数超过预设的天
                                days = taskRunMode.AlarmClock.Value.Day;
                            }
                            taskRunMode.NextExecuteTime = new DateTime(nextYear,
                                nextMonth,
                                days,
                                taskRunMode.AlarmClock.Value.Hour,
                                taskRunMode.AlarmClock.Value.Minute,
                                0);
                        }
                        #endregion
                    }
                    else if (taskRunMode.AlarmMode.Value == CPPEI.ETL.Domain.DEF.TaskAlarmMode.PreWeek)
                    {
                        #region week
                        if (taskRunMode.LastExecutedTime == null)
                        {
                            if (now.DayOfWeek == taskRunMode.AlarmClock.Value.DayOfWeek)
                            {
                                taskRunMode.NextExecuteTime = new DateTime(now.Year,
                                    now.Month,
                                    now.Day,
                                    taskRunMode.AlarmClock.Value.Hour,
                                    taskRunMode.AlarmClock.Value.Minute,
                                    0);
                            }
                        }
                        else
                        {
                            // 添加7天
                            DateTime nextTime = new DateTime(now.Year,
                                    now.Month,
                                    now.Day,
                                    taskRunMode.AlarmClock.Value.Hour,
                                    taskRunMode.AlarmClock.Value.Minute,
                                    0);

                            taskRunMode.NextExecuteTime = nextTime.AddDays(7);
                        }
                        #endregion
                    }
                    else if (taskRunMode.AlarmMode.Value == CPPEI.ETL.Domain.DEF.TaskAlarmMode.PreDay)
                    {
                        #region day
                        if (taskRunMode.LastExecutedTime == null)
                        {
                            // 第一次运行（monitor启动之后）
                            taskRunMode.NextExecuteTime = new DateTime(now.Year,
                                now.Month,
                                now.Day,
                                taskRunMode.AlarmClock.Value.Hour,
                                taskRunMode.AlarmClock.Value.Minute,
                                0);
                        }
                        else
                        {
                            // 添加一天
                            DateTime  nextTime = new DateTime(now.Year,
                                now.Month,
                                now.Day,
                                taskRunMode.AlarmClock.Value.Hour,
                                taskRunMode.AlarmClock.Value.Minute,
                                0);

                            taskRunMode.NextExecuteTime = nextTime.AddDays(1);
                        }
                        #endregion
                    }

                    if (taskRunMode.NextExecuteTime != null)
                    {
                        Logger.InfoToTag(Library.LogTAG, string.Format("设置任务:{0},{1}的下次执行时间为:{2}", alarmTask.Id, alarmTask.Name, taskRunMode.NextExecuteTime.Value));
                    }
                }
                #endregion

                #region 监测运行时间
                if (taskRunMode.NextExecuteTime != null)
                {
                    if (taskRunMode.NextExecuteTime.Value.Ticks / s_muniteTicks < now.Ticks / s_muniteTicks)
                    {
                        // 下次执行时间小于当前时间，已经过点了，执行下一次吧
                        taskRunMode.LastExecutedTime = taskRunMode.NextExecuteTime;
                        taskRunMode.NextExecuteTime = null;
                        Logger.InfoToTag(Library.LogTAG, string.Format("任务:{0},{1}已经错过这一次执行时间，跳过这次执行", alarmTask.Id, alarmTask.Name));
                    }
                    else
                    {
                        // 任务还没有执行
                        if (now.Year == taskRunMode.NextExecuteTime.Value.Year
                            && now.Month == taskRunMode.NextExecuteTime.Value.Month
                            && now.Day == taskRunMode.NextExecuteTime.Value.Day
                            && now.Hour == taskRunMode.NextExecuteTime.Value.Hour
                            && now.Minute == taskRunMode.NextExecuteTime.Value.Minute)
                        {
                            // 执行任务
                            taskRunMode.LastExecutedTime = taskRunMode.NextExecuteTime;
                            taskRunMode.NextExecuteTime = null;
                            Logger.InfoToTag(Library.LogTAG, string.Format("执行任务:{0},{1}", alarmTask.Id, alarmTask.Name));
                            HttpClient.Http.PostToServer(alarmTask);
                        }
                    }
                }
                #endregion
            }
        }
    }
}
